package handler

import (
	"context"
	"errors"
	"fmt"
	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog"
	"github.com/spf13/cast"
	"net/http"
	"net/url"
	"path/filepath"
	"ruoyi-go-echo-ddd/internal/application"
	"ruoyi-go-echo-ddd/internal/infrastructure/http/response"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"
	"strconv"
	"strings"
	"time"
)

type MinioHandler struct {
	minioApp *application.MinioApplication
}

func NewMinioHandler(a *application.MinioApplication) *MinioHandler {
	return &MinioHandler{
		minioApp: a,
	}
}

func (c *MinioHandler) UploadHandler(e echo.Context) error {
	// 解析表单，设置缓存为 32MB
	form, err := GetEchoForm(e, 32<<20)
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}

	respUrl, err := c.minioApp.Upload(e, form, "test")
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	response.NewResponse(e, 200, "上传成功", respUrl)
	return nil
}

func (c *MinioHandler) UploadFilesHandler(e echo.Context) error {
	// 解析表单，设置缓存为 32MB
	form, err := GetEchoForm(e, 32<<20)
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	urlList, err := c.minioApp.UploadFiles(e, form, "test")
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	response.NewResponse(e, 200, "上传成功", urlList)
	return nil
}

func (c *MinioHandler) DeleteHandler(e echo.Context) error {
	param := map[string]any{}
	if err := BindParam(e, &param); err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	count, err := c.minioApp.Delete(e, cast.ToString(param["bucket"]), cast.ToStringSlice(param["objectList"]))
	if err != nil {
		response.NewRespCodeMsg(e, http.StatusInternalServerError, err.Error())
		return err
	}
	response.NewRespCodeMsg(e, 200, fmt.Sprintf("成功删除：%d个文件", count))
	return nil
}

func (c *MinioHandler) UploadPrefixHandler(e echo.Context) error {
	// 解析表单，设置缓存为 32MB
	form, err := GetEchoForm(e, 32<<20)
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}

	respUrl, err := c.minioApp.UploadPrefix(e, form, "test")
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	response.NewResponse(e, 200, "上传成功", respUrl)
	return nil
}

// var downloadCounter int64

func (c *MinioHandler) DownloadByteHandler(e echo.Context) error {
	fileName := "vlc-3.0.20-arm64.dmg"
	// 生成唯一文件名
	uniqueFileName := url.PathEscape(fmt.Sprintf("%s_%s%s",
		strings.TrimSuffix(fileName, filepath.Ext(fileName)),
		utils.NormalUUID(),
		filepath.Ext(fileName)))

	// 设置响应头（必须在写入响应体之前）
	e.Response().Header().Set("Content-Type", "application/octet-stream")
	e.Response().Header().Set("Content-Disposition",
		fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s", uniqueFileName, uniqueFileName))

	// 尝试获取文件大小并设置Content-Length
	objInfo, err := c.minioApp.GetStatObject(e, "test", fileName)
	if err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return nil
	}
	e.Response().Header().Set("Content-Length", strconv.FormatInt(objInfo.Size, 10))
	_, _, err = c.minioApp.FileInputByte(e, e.Response().Writer, "test", fileName, uniqueFileName, 5*1024*1024)
	if err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msgf("下载文件===%s出错了", fileName)
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return nil
	}

	// 原子增加计数器
	// counter := atomic.AddInt64(&downloadCounter, 1)

	// // 生成带序号的文件名
	// uniqueFileName := fmt.Sprintf("%s (%d)%s",
	// 	strings.TrimSuffix(fileName, filepath.Ext(fileName)),
	// 	counter,
	// 	filepath.Ext(fileName))

	// 将[]byte字节数据写入响应
	// _, err = e.Response().Writer.Write(b)
	// if err != nil {
	// 	// 处理写入错误
	// 	response.NewRespCodeErr(e, http.StatusInternalServerError, err)
	// 	return err
	// }
	return nil
}

func (c *MinioHandler) DownloadLocalHandler(e echo.Context) error {
	if err := c.minioApp.DownloadObjectWithResume(e, "test", "vlc-3.0.20-arm64.dmg", "vlc-1111.dmg", 20*1024*1024); err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	response.NewRespCodeMsg(e, 200, "下载完成")
	return nil
}

func (c *MinioHandler) DownloadResponseHandler(e echo.Context) error {

	e.Response().Header().Set("Content-Type", "application/octet-stream")
	e.Response().Header().Set("Content-Transfer-Encoding", "binary")

	fileName := "vlc-3.0.20-arm64.dmg"
	timestamp := time.Now().Local().Format("20060102150405.000")
	extName := filepath.Ext(fileName)

	// 增加时间戳
	uniqueFileName := url.PathEscape(fmt.Sprintf("%s_%s%s",
		strings.TrimSuffix(fileName, extName),
		strings.Replace(timestamp, ".", "", 1),
		extName))
	e.Response().Header().Set("Content-Disposition",
		fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s", uniqueFileName, uniqueFileName))

	if err := c.minioApp.DownloadResponseWithResume(e, e.Response().Writer, "test",
		fileName, 20*1024*1024); err != nil {
		response.NewRespCodeErr(e, http.StatusInternalServerError, err)
		return err
	}
	return nil
}

// DownloadListToZipHandler 下载文件到zip处理器
func (c *MinioHandler) DownloadListToZipHandler(e echo.Context) error {
	form, err := e.MultipartForm()
	if err != nil {
		response.NewRespCodeErr(e, http.StatusBadRequest, err)
		return err
	}
	bucket := ""
	if valList, ok := form.Value["bucket"]; ok && len(valList) > 0 {
		bucket = valList[0]
	}
	var objectList []string
	if objectMap, ok := form.Value["objectList"]; ok && len(objectMap) > 0 {
		for _, item := range objectMap {
			objectList = append(objectList, item)
		}
	}

	zerolog.DefaultContextLogger.Debug().Msgf("下载文件zip参数bucket===%s,objectList===%s", bucket, objectList)

	replace := strings.Replace(time.Now().Local().Format("20060102150405.000"), ".", "", 1)
	uniqueFileName := url.PathEscape(fmt.Sprintf("%s_%s.zip", utils.ShortUUID(), replace))
	e.Response().Header().Set("Content-Disposition",
		fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s", uniqueFileName, uniqueFileName))

	if err = c.minioApp.DownloadObjectListToZip(e, e.Response().Writer, bucket, objectList, 64*1024); err != nil {
		if errors.Is(err, context.Canceled) {
			// 客户端取消，不返回错误
			return nil
		}
		response.NewRespCodeMsg(e, 500, "下载失败")
		return err
	}
	return nil
}

// DownloadListToZipParallelHandler 并行下载文件到zip处理器
func (c *MinioHandler) DownloadListToZipParallelHandler(e echo.Context) error {
	form, err := e.MultipartForm()
	if err != nil {
		response.NewRespCodeErr(e, http.StatusBadRequest, err)
		return err
	}
	bucket := ""
	if valList, ok := form.Value["bucket"]; ok && len(valList) > 0 {
		bucket = valList[0]
	}
	var objectList []string
	if objectMap, ok := form.Value["objectList"]; ok && len(objectMap) > 0 {
		for _, item := range objectMap {
			objectList = append(objectList, item)
		}
	}

	zerolog.DefaultContextLogger.Debug().Msgf("下载文件zip参数bucket===%s,objectList===%s", bucket, objectList)

	replace := strings.Replace(time.Now().Local().Format("20060102150405.000"), ".", "", 1)
	uniqueFileName := url.PathEscape(fmt.Sprintf("%s_%s.zip", utils.ShortUUID(), replace))
	e.Response().Header().Set("Content-Disposition",
		fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s", uniqueFileName, uniqueFileName))

	if err = c.minioApp.DownloadObjectListToZipParallel(e, e.Response().Writer, bucket, objectList, 64*1024, 3); err != nil {
		if errors.Is(err, context.Canceled) {
			// 客户端取消，不返回错误
			return nil
		}
		response.NewRespCodeMsg(e, 500, "下载失败")
		return err
	}
	return nil
}
